<?php
/**
 * Server Instance class
 *
 * Use this class twice for connection to 2 different databases in MySQLcompare
 *
 * PHP version 5
 *
 * Copyright (C) 2012 Ewald van Gemert (ewald@vangee.nl)
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 
 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * @category   Development tool
 * @package    MySQLcompare
 * @author     Ewald van Gemert <ewald@vangee.nl>
 * @license    MIT 3
 * @version    SVN: 
 * @link       http://code.google.com/p/mysqlcompare
 * @since      File available since Release 0.9
 */

require_once 'compare.base.class.php';
// ###########################################################################
// Class van een Server Item
// ###########################################################################
class SYNC extends COMPAREBASE {
	private $synckeys = array();

	// ****************************************************************************
	//  Script sync actions
	// ****************************************************************************
	// Sync complete table or definition
	private function syncTableScript($action, $tblFrom, $tblTo) {
		// Rename original target (if exists)
		$sql = array();
		if (in_array($tblTo, $this->tablesb)) $sql[] = "RENAME TABLE `{$tblTo}` TO `{$tblTo}_tempsynctable_REMOVE`";
		
		// Create new target
		$row = $this->dba->get_row("SHOW CREATE TABLE `{$tblFrom}`");
		$sql[] = $row[1];

		if ($action=='all') {
			// Copy all rows form OLD to NEW table
			$rows = $this->dba->get_rows("SELECT * FROM `{$tblFrom}`");
			foreach ($rows as $row) {
				foreach ($row as &$fld) $fld = $this->dba->escape($fld);
				$sql[] = "INSERT INTO `{$tblTo}` VALUES ('".implode("','", $row)."')";
			}
		} else {
			if (in_array($tblTo, $this->tablesb)) {
				// Keep old data (is stored in the temp table)
				// Only copy matching collumns, so get column intersect.
				$metaA = $this->dba->tblmeta($tblFrom, QUIET);
				$metaB = $this->dbb->tblmeta($tblTo, QUIET);
				$this->metaCompare($metaA, $metaB);			
				$fldlist = "`".implode("`,`", $this->colsi)."`";
				$sql[] = "INSERT INTO `{$tblTo}` ({$fldlist}) SELECT {$fldlist} FROM `{$tblTo}_tempsynctable_REMOVE`";
			}
		}
		
		// Drop temp table (if renamed earlier)
		if (in_array($tblTo, $this->tablesb)) $sql[] = "DROP TABLE `{$tblTo}_tempsynctable_REMOVE`";// <1-- IF TABLE EXISTS!
		return $sql;
	}
	
	// ****************************************************************************
	//  Local sync actions
	// ****************************************************************************
	// Sync complete table or definition
	private function syncTableLocal($action, $tblFrom, $tblTo) {
		// Get original table definitions
		$metaA = $this->dba->tblmeta($tblFrom, QUIET);
		$metaB = $this->dbb->tblmeta($tblTo, QUIET);
		$this->metaCompare($metaA, $metaB);			
		$fldlist = "`".implode("`,`", $this->colsi)."`";
	
		// Rename target
		if (in_array($tblTo, $this->tablesb)) $this->dbb->exec("RENAME TABLE `{$tblTo}` TO `{$tblTo}_tempsynctable_REMOVE`", QUIET);
		// Create new target
		$this->dbb->exec("CREATE TABLE `{$tblTo}` LIKE `{$this->dba->database()}`.`{$tblFrom}`");
		
		if ($action=='all') {
			// Copy all rows form Source to Target table
			$this->dbb->exec("INSERT INTO `{$tblTo}` SELECT * FROM `{$this->dba->database()}`.`{$tblFrom}`");
		} else {
			if (in_array($tblTo, $this->tablesb)) {
				// Keep old data (is stored in the temp table)
				// Only copy collumns that exist in `From` AND `To` table
				$this->dbb->exec("INSERT INTO `{$tblTo}` ({$fldlist}) SELECT {$fldlist} FROM `{$tblTo}_tempsynctable_REMOVE`");
			}
		}
		if (in_array($tblTo, $this->tablesb)) $this->dbb->exec("DROP TABLE `{$tblTo}_tempsynctable_REMOVE`", QUIET);
	}
	
	// Replace all rows
	private function syncAllrowsLocal($action, $tblFrom, $tblTo) {
		return $this->dbb->exec("REPLACE INTO `{$tblTo}` SELECT * FROM `{$this->dba->database()}`.`{$tblFrom}`");
	}

	private function syncNewrowsLocal($action, $tblFrom, $tblTo) {
		// Rename original target
		$this->dbb->exec("RENAME TABLE `{$tblTo}` TO `{$tblTo}_tempsynctable_REMOVE`");
		// Create new target
		$this->dbb->exec("CREATE TABLE `{$tblTo}` LIKE `{$tblTo}_tempsynctable_REMOVE`");
		// Copy all rows form source to taget table
		$metaA = $this->dba->tblmeta($tblFrom, QUIET);
		$metaB = $this->dbb->tblmeta($tblTo, QUIET);
		$this->metaCompare($metaA, $metaB);			
		$fldlist = "`".implode("`,`", $this->colsi)."`";	
		$this->dbb->exec("INSERT INTO `{$tblTo}` ({$fldlist}) SELECT {$fldlist} FROM `{$tblFrom}`");
		// Copy all rows form original-target to target table
		//   hereby replaceing all source rows with the original target
		$this->dbb->exec("REPLACE INTO `{$tblTo}` SELECT * FROM `{$tblTo}_tempsynctable_REMOVE`");
		$this->dbb->exec("DROP TABLE `{$tblTo}_tempsynctable_REMOVE`", QUIET);
	}

	private function syncDel($action, $tbl) {
		// Delete the table you are syncing to (=B). (Is not syncing actually)
		return $this->dbb->exec("DROP TABLE `{$tbl}`");
	}
	
	// ***********************************************************************
	// public functions
	// Synchronise allways from A -> B
	// Only table B is altered.
	// *********************************************************************** 
	public function doSync($tblFrom, $tblTo, $action) {
		// TODO: Before doSync, you can set property `keys` to use alternative combining keys.
		$obj = array("sync" => array("tablefrom" => "$tblFrom", "tablefrom" => "$tblTo", "action" => "$action"));
		$result = false;
		ob_start();
		
		if ($this->dba->identifier()==$this->dbb->identifier()) {
			$obj['sync']['span']='local';
			// Local database actions (on same server)
			switch ($action) {
				case 'all':
				case 'definition':
					$result = $this->syncTableLocal($action, $tblFrom, $tblTo);
					break;
				case 'allrows':
					$result = $this->syncAllrowsLocal($action, $tblFrom, $tblTo);
					break;
				case 'newrows':
					$result = $this->syncNewrowsLocal($action, $tblFrom, $tblTo);
					break;
				case 'del':
					// use standard function. Is never spanning multiple servers
					$result = $this->syncDel($action, $tblTo);
					break;
			}
		} else {
			// Remote database actions (spanning different servers)
			$obj['sync']['span']='remote';
			switch ($action) {
				case 'all':
				case 'definition':
					$result = $this->syncTableScript($action, $tblFrom, $tblTo);
					$this->dbb->exec($result);			
					break;
				case 'allrows':
					$result = $this->syncAllrowsRemote($action, $tblFrom, $tblTo);
					break;
				case 'newrows':
					$result = $this->syncNewrowsRemote($action, $tblFrom, $tblTo);
					break;
				case 'del':
					// use standard function. Is never spanning multiple servers
					$result = $this->syncDel($action, $tblTo);
					break;
			}
		}
	
		$obj['sync']['result']=$result;
		$obj['sync']['message']=ob_get_contents();
		ob_end_clean();
	
		return $obj;
	}
}
